package DEEPERsource.DEEPERsource.source.jung.entities;

import java.io.BufferedReader;
import java.io.IOException;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;

import jung.entities.DependencyVertex;

import edu.uci.ics.jung.graph.DirectedEdge;
import edu.uci.ics.jung.graph.Vertex;
import edu.uci.ics.jung.graph.impl.DirectedSparseEdge;
import edu.uci.ics.jung.graph.impl.SparseTree;
import edu.uci.ics.jung.graph.impl.SparseVertex;
import edu.uci.ics.jung.utils.UserData;
import graph.Keys;

@Deprecated
public class Path extends SparseTree implements Keys{
	
	private Vertex leaf1, leaf2;
	
	public Path(Vertex root) {
		super(root);
	}
	
	public Vertex findVertex(int index) {
		for (Object vert : mVertices) {
			Vertex _vert = (Vertex) vert;
			if (_vert.getUserDatum(INDEX).toString().equals(Integer.toString(index))) {
				return _vert;
			}
		}
		return null;
	}

	/**
	 * Print path's string representetion
	 */
	@SuppressWarnings("unchecked")
	public String toString(){
		StringBuffer sbLeft = new StringBuffer("");
		Vertex v = leaf1;
		Set<DirectedEdge> in = v.getInEdges();
		while(!in.isEmpty()){
			sbLeft.append((String)v.getUserDatum(LABEL));
			DirectedEdge e = in.iterator().next();
			sbLeft.append("<-").append(e.getUserDatum(LABEL)).append("-");
			v = e.getSource();
			in = v.getInEdges();
		}
		StringBuffer sbRight = new StringBuffer("");
		v = leaf2;
		in = v.getInEdges();
		while(!in.isEmpty()){
			sbRight.insert(0,(String)v.getUserDatum(LABEL));
			DirectedEdge e = in.iterator().next();
			sbRight.insert(0,"->").insert(0,e.getUserDatum(LABEL)).insert(0,"-");
			v = e.getSource();
			in = v.getInEdges();
		}
		return sbLeft.toString().concat((String)mRoot.getUserDatum(LABEL)).concat(sbRight.toString());
	}
	
	//--------------NON INTERFACE PUBLIC METHODS---------------------
	
	/**
	 * Prints path in ARFF format
	 */
	@SuppressWarnings("unchecked")
	public String arffDepString(){
		StringBuffer sbLeft = new StringBuffer("");
		Set<DirectedEdge> in = leaf1.getInEdges();
		while(!in.isEmpty()){
			DirectedEdge e = in.iterator().next();
			sbLeft.insert(0,(String)e.getUserDatum(LABEL)+"(up),");		
			in = e.getSource().getInEdges();
		}
		StringBuffer sbRight = new StringBuffer("");
		in = leaf2.getInEdges();
		while(!in.isEmpty()){
			DirectedEdge e = in.iterator().next();
			sbRight.insert(0,(String)e.getUserDatum(LABEL)+"(down),");		
			in = e.getSource().getInEdges();
		}
		sbRight.deleteCharAt(sbRight.length()-1);
		return sbLeft.toString().concat(sbRight.toString());
	}
	
	public int getLeftDepth(){
		Set<DirectedEdge> in = leaf1.getInEdges();
		int depth = 0;
		while(!in.isEmpty()){
			depth++;
			DirectedEdge e = in.iterator().next();
			in = e.getSource().getInEdges();
		}
		return depth;
	}
	
	public int getRightDepth(){
		Set<DirectedEdge> in = leaf2.getInEdges();
		int depth = 0;
		while(!in.isEmpty()){
			depth++;
			DirectedEdge e = in.iterator().next();
			in = e.getSource().getInEdges();
		}
		return depth;
	}
	
	public int getLabelOccursInLeft(String label){
		Set<DirectedEdge> in = leaf1.getInEdges();
		int occ = 0;
		while(!in.isEmpty()){
			DirectedEdge e = in.iterator().next();
			if(e.getSource().getUserDatum(Keys.LABEL).toString().equals(label)){
				occ++;
			}
			in = e.getSource().getInEdges();
		}
		return occ;
	}
	
	public int getLabelOccursInRight(String label){
		Set<DirectedEdge> in = leaf2.getInEdges();
		int occ = 0;
		while(!in.isEmpty()){
			DirectedEdge e = in.iterator().next();
			if(e.getSource().getUserDatum(Keys.LABEL).toString().equals(label)){
				occ++;
			}
			in = e.getSource().getInEdges();
		}
		return occ;
	}
	
	public Vertex getLeaf1() {
		return leaf1;
	}

	public void setLeaf1(Vertex leaf1) {
		this.leaf1 = leaf1;
	}

	public Vertex getLeaf2() {
		return leaf2;
	}

	public void setLeaf2(Vertex leaf2) {
		this.leaf2 = leaf2;
	}
	
	public String serialize() {
		StringBuffer sb = new StringBuffer();
		sb.append(mRoot.getClass().getCanonicalName());
		sb.append("\t");
		sb.append(mRoot.getUserDatum(INDEX));
		sb.append("\t");
		sb.append(mRoot.getUserDatum(LABEL));
		sb.append("\n");
		for (Object o : mVertices) {
			if (o.equals(mRoot)) {
				continue;
			}
			Vertex v = (Vertex) o;
			sb.append(v.getClass().getCanonicalName());
			sb.append("\t");
			sb.append(v.getUserDatum(INDEX));
			sb.append("\t");
			sb.append(v.getUserDatum(LABEL));
			sb.append("\n");
		}
		sb.append("\nEDGES\n");
		//some serialization tricks
		//we need to arrange an order of edges in order to deresialize properly
		Set<DirectedEdge> edges = new HashSet<DirectedEdge>(mEdges);
		Set<Vertex> vSet = new HashSet<Vertex>();
		vSet.add(mRoot);
		while(!edges.isEmpty()){
			for(Iterator<DirectedEdge> i = edges.iterator(); i.hasNext();){
				DirectedEdge e = i.next();
				if(vSet.contains(e.getSource())){
					sb.append(e.getSource().getUserDatum(INDEX));
					sb.append("\t");
					sb.append(e.getDest().getUserDatum(INDEX));
					sb.append("\t");
					sb.append(e.getUserDatum(INDEX));
					sb.append("\t");
					sb.append(e.getUserDatum(LABEL));
					sb.append("\n");
					vSet.add(e.getDest());
					i.remove();
				}
			}
		}
		sb.append("\nLEAVES\n");
		sb.append(leaf1.getUserDatum(INDEX));
		sb.append("\t");
		sb.append(leaf2.getUserDatum(INDEX));
		sb.append("\n");
		return sb.toString();
	}

	public static Path deserialize(BufferedReader stream) throws IOException {
		String s;
		Path tree = null;
		boolean first = true;
		boolean vertices = true;
		boolean edges = false;
		while ((s = stream.readLine()) != null) {
			if(s.equals("")){
				continue;
			}
			if (s.equals("EDGES")) {
				vertices = false;
				edges = true;
				continue;
			}
			if (s.equals("LEAVES")) {
				edges = false;
				continue;
			}
			String[] split = s.split("\t");
			if (vertices) {
				Vertex v;
				try {
					v = (Vertex) Class.forName(split[0]).newInstance();
				} catch (Exception e) {
					e.printStackTrace();
					return null;
				}
				v.setUserDatum(INDEX, split[1], UserData.SHARED);
				v.setUserDatum(LABEL, split[2], UserData.SHARED);
				if (first) {
					tree = new Path(v);
					first = false;					
				}else{
					tree.addVertex(v);
				}
			} else if(edges){
				Vertex v1 = tree.findVertex(Integer.parseInt(split[0]));
				Vertex v2 = tree.findVertex(Integer.parseInt(split[1]));
				DirectedEdge e = new DirectedSparseEdge(v1, v2);
				e.setUserDatum(INDEX, split[2], UserData.SHARED);
				e.setUserDatum(LABEL, split[3], UserData.SHARED);
				tree.addEdge(e);
			} else{
				tree.leaf1 = tree.findVertex(Integer.parseInt(split[0]));
				tree.leaf2 = tree.findVertex(Integer.parseInt(split[1]));
			}
		}
		return tree;
	}

}
